@using Blazor.Serialization.Extensions

<MudStack>
    <MudToolBar DisableGutters="true">
        <MudText Typo="Typo.h4">@Title</MudText>
        <MudSpacer />
        @ChildContent
        <MudPaper Outlined="true" Class="flex-grow-1 pb-2 pl-3">
            <MudTextField @bind-Value="_filter" Placeholder="Search products" Adornment="Adornment.Start"
                AdornmentIcon="@Icons.Material.Filled.Search" IconSize="Size.Medium" Class="mt-n2" DisableUnderLine="true">
            </MudTextField>
        </MudPaper>
    </MudToolBar>
    <MudTable Items=@Products Hover="true" Breakpoint="Breakpoint.Sm" AllowUnsorted=true Filter=OnFilter
              CanCancelEdit=true Context="product" Dense=true FixedHeader=true RowsPerPage=10 RowEditCommit=OnEdit
              RowEditPreview=BackupItem RowEditCancel=RevertEditChanges ReadOnly=false SortLabel="Sort By"
              CancelEditTooltip="Discard changes..." CommitEditTooltip="Save changes..." Outlined="true"
              IsEditRowSwitchingBlocked=true>
        <HeaderContent>
            <MudTh>
                <MudTableSortLabel SortBy=@(new Func<ProductDetails, object>(p => p.Name))>
                    Name
                </MudTableSortLabel>
            </MudTh>
            <MudTh>
                <MudTableSortLabel SortBy=@(new Func<ProductDetails, object>(p => p.Description))>
                    Description
                </MudTableSortLabel>
            </MudTh>
            <MudTh>
                <MudTableSortLabel SortBy=@(new Func<ProductDetails, object>(p => p.Quantity))>
                    Quantity
                </MudTableSortLabel>
            </MudTh>
            <MudTh>
                <MudTableSortLabel SortBy=@(new Func<ProductDetails, object>(p => p.UnitPrice))>
                    Price
                </MudTableSortLabel>
            </MudTh>
        </HeaderContent>
        <RowTemplate>
            <MudTd DataLabel="Name">@product.Name</MudTd>
            <MudTd DataLabel="Description">@product.Description</MudTd>
            <MudTd DataLabel="Quantity">@product.Quantity.ToString("N0")</MudTd>
            <MudTd DataLabel="Price">@product.UnitPrice.ToString("C2")</MudTd>
        </RowTemplate>
        <RowEditingTemplate>
            <MudTd DataLabel="Name">
                <MudTextField @bind-Value=@product.Name Required />
            </MudTd>
            <MudTd DataLabel="Description">
                <MudTextField @bind-Value=@product.Description Required />
            </MudTd>
            <MudTd DataLabel="Quantity">
                <MudNumericField @bind-Value=@product.Quantity Required Min="1" />
            </MudTd>
            <MudTd DataLabel="Price">
                <MudNumericField T="decimal" @bind-Value=@product.UnitPrice Required Min="0.01m" />
            </MudTd>
        </RowEditingTemplate>
        <PagerContent>
            <MudTablePager />
        </PagerContent>
    </MudTable>
</MudStack>

@code {
    string? _filter;

    ProductDetails? _productBeforeEdit;

    [Parameter, EditorRequired]
    public HashSet<ProductDetails> Products { get; set; } = null!;

    [Parameter, EditorRequired]
    public string Title { get; set; } = null!;

    [Parameter]
    public RenderFragment? ChildContent { get; set; }

    [Parameter, EditorRequired]
    public EventCallback<ProductDetails> EditProduct { get; set; }

    void OnEdit(object model)
    {
        if (model is ProductDetails product &&
            EditProduct.HasDelegate)
        {
            _ = EditProduct.InvokeAsync(product);
        }
    }

    void BackupItem(object model)
    {
        if (model is ProductDetails product)
        {
            _productBeforeEdit = product;
        }
    }

    void RevertEditChanges(object model)
    {
        if (model is ProductDetails product &&
            _productBeforeEdit is not null)
        {
            model = _productBeforeEdit with { };
        }
    }

    bool OnFilter(ProductDetails product) => product.MatchesFilter(_filter);
}